﻿// Copyright (c) 2014 Jonathan Magnan (http://jonathanmagnan.com/).
// All rights reserved (http://zzzproject.com/sqlbulkcopy-extensions/).
// Licensed under MIT License (MIT) (https://zsqlbulkcopy.codeplex.com/license/).
using System;
using System.Collections.Generic;
using System.Data;
using System.Reflection;
#if NET20
using Z.Net.Legacy20;
#elif NET35 || NET40
using System.Linq;
#endif

namespace Z.Net.Extensions
{
    internal partial class SqlBulkOperation
    {
        /// <summary>
        ///     Sets internal data source generic type.
        /// </summary>
        public void SetInternalDataSourceGenericType()
        {
            List<object> datasource = DataSourceAsList;
            var dt = new DataTable();
            MappingList.ForEach(x => dt.Columns.Add(x.SourceColumn));

            Type type = DataSource is object[] ? DataSource.GetType().GetElementType() : DataSource.GetType().GetGenericArguments()[0];
            PropertyInfo[] properties = type.GetProperties(BindingFlags.Public | BindingFlags.Instance);
            FieldInfo[] fields = type.GetFields(BindingFlags.Public | BindingFlags.Instance);

#if NET20
            IEnumerable<PropertyInfo> propertiesWhere = IEnumerableExtensions.Where(properties, x => dt.Columns.Contains(x.Name));
            IEnumerable<FieldInfo> fieldsWhere = IEnumerableExtensions.Where(fields, x => dt.Columns.Contains(x.Name));
            properties = new List<PropertyInfo>(propertiesWhere).ToArray();
            fields = new List<FieldInfo>(fieldsWhere).ToArray();
#elif NET35 || NET40
            properties = properties.Where(x => dt.Columns.Contains(x.Name)).ToArray();
            fields = fields.Where(x => dt.Columns.Contains(x.Name)).ToArray();
#endif

            bool isTypeAdded = false;

            // Enumrate all items
            foreach (object item in datasource)
            {
                if (!isTypeAdded)
                {
                    foreach (PropertyInfo property in properties)
                    {
                        Type dataType = property.PropertyType;
                        if (dataType.IsGenericType)
                        {
                            dataType = dataType.GetGenericArguments()[0];
                        }
                        dt.Columns[property.Name].DataType = dataType;
                    }

                    foreach (FieldInfo field in fields)
                    {
                        Type dataType = field.FieldType;
                        if (dataType.IsGenericType)
                        {
                            dataType = dataType.GetGenericArguments()[0];
                        }
                        dt.Columns[field.Name].DataType = dataType;
                    }

                    isTypeAdded = true;
                }

                DataRow dr = dt.NewRow();

                foreach (PropertyInfo property in properties)
                {
                    object value = property.GetValue(item, null);
                    dr[property.Name] = value ?? DBNull.Value;
                }

                foreach (FieldInfo field in fields)
                {
                    object value = field.GetValue(item);
                    dr[field.Name] = value ?? DBNull.Value;
                }

                dt.Rows.Add(dr);
            }

            InternalDataSource = dt;
        }
    }
}